package order

import (
	"context"
	"database/sql"
	"errors"
	"strconv"
	"strings"
	"video-api/internal/consts"
	"video-api/internal/dao"
	"video-api/internal/middleware"
	"video-api/internal/model/entity"
	"video-api/internal/model/input"
	"video-api/internal/model/out"
	"video-api/internal/service"
	"video-api/utility"
	"video-api/utility/metrics"

	"github.com/gogf/gf/errors/gerror"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/frame/g"
)

func init() {
	service.RegisterOrderService(&orderService{})
}

type orderService struct{}

func (s *orderService) GetOrderList(ctx context.Context, param *input.OrderList) (res []*entity.Orders, count int, err error) {
	orderModel := dao.Orders.Ctx(ctx)

	if param.UserId != 0 {
		orderModel = orderModel.Where("user_id = ?", param.UserId)
	}
	if param.Status != "" {
		orderModel = orderModel.Where("status = ?", param.Status)
	}
	if param.Page != 0 && param.PageSize != 0 {
		orderModel = orderModel.Page(param.Page, param.PageSize)
	}
	err = orderModel.ScanAndCount(&res, &count, true)
	if err != nil {
		g.Log().Error(ctx, "GetOrderList-Page err: ", err)
		return nil, 0, err
	}
	// 获取商品信息
	return res, count, nil
}

// UnlockShortDrama 解锁短剧
func (s *orderService) UnlockShortDrama(ctx context.Context, param *input.UnlockDrama) (*out.ShortDramaEpisodesEntity, error) {
	// 判断这部剧集是否被解锁过
	exist, err := dao.ShortDramaUnlocks.Ctx(ctx).Where("user_id = ? AND short_drama_episode_id = ?", param.UserId, param.EpisodeId).Exist()
	if err != nil {
		g.Log().Error(ctx, "orderService UnlockShortDrama Exist err: ", err, g.Map{"userId": param.UserId, "episodeId": param.EpisodeId})
		return nil, err
	}
	if exist {
		g.Log().Error(ctx, "orderService UnlockShortDrama isUnlock err: ", err)
		return nil, errors.New("该剧集已经解锁")
	}
	episodes := new(out.ShortDramaEpisodesEntity)
	err = dao.ShortDramaEpisodes.Ctx(ctx).Where("id = ?", param.EpisodeId).Scan(episodes)
	if err != nil && !errors.Is(err, sql.ErrNoRows) {
		g.Log().Error(ctx, "orderService UnlockShortDrama GetDetail err: ", err)
		return nil, err
	}
	if episodes.Id == 0 {
		return nil, errors.New("短剧集不存在")
	}
	err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		userModel := dao.Users.Ctx(ctx)
		// 查看用户余额是否充足
		userInfo := new(entity.Users)
		err := userModel.Where("id = ?", param.UserId).Scan(&userInfo)
		if err != nil {
			g.Log().Error(ctx, "UnlockShortDrama GetUserInfo err: ", err, g.Map{"userId": param.UserId})
			return err
		}
		if (userInfo.Coins+userInfo.Bonus)-param.Coins < 0 {
			return errors.New("用户余额不足")
		}
		// 扣除用户余额
		if userInfo.Bonus < param.Coins {
			// 额外硬币不够，则扣款主硬币
			userInfo.Coins -= param.Coins - userInfo.Bonus
			userInfo.Bonus = 0
		} else {
			userInfo.Bonus -= param.Coins
		}
		result, err := userModel.Where("id = ?", param.UserId).Update(userInfo)
		if err != nil {
			g.Log().Error(ctx, "UnlockShortDrama Update err: ", err, g.Map{"userId": param.UserId})
			return err
		}
		var row int64
		if row, err = result.RowsAffected(); err != nil {
			g.Log().Error(ctx, "UnlockShortDrama Update RowsAffected err: ", err, g.Map{"userId": param.UserId})
			return err
		} else if row == 0 {
			g.Log().Error(ctx, "UnlockShortDrama Update No Row", g.Map{"userId": param.UserId})
			return errors.New("未找到用户信息")
		}
		// 存入短剧解锁表
		_, err = dao.ShortDramaUnlocks.Ctx(ctx).Save(&entity.ShortDramaUnlocks{
			UserId:              userInfo.Id,
			ShortDramaId:        param.ShortDramaId,
			ShortDramaEpisodeId: param.EpisodeId,
			Coins:               param.Coins,
			UnlockType:          consts.UNLOCAK_TYPE_SINGLE, // 默认单集解锁
		})
		if err != nil {
			g.Log().Error(ctx, "orderService UnlockShortDrama Save err: ", err)
			return err
		}
		return nil
	})
	if err != nil {
		g.Log().Error(ctx, "UnlockShortDrama Transaction err: ", err)
		return nil, err
	}
	shortDrama := new(entity.ShortDrama)
	err = dao.ShortDrama.Ctx(ctx).Where("id = ?", episodes.ShortDramaId).Scan(shortDrama)
	if err != nil {
		g.Log().Error(ctx, "UnlockShortDrama GetShortDrama err: ", err)
		return nil, err
	}
	episodes.IsUnLock = true
	episodes.CostCoin = param.Coins
	episodes.EpisodeImg = shortDrama.CoverImg
	episodes.Title = shortDrama.ShortName
	return episodes, nil
}

// GetUnlockShortDramaList 查找短剧解锁列表 TODO userid
func (s *orderService) GetUnlockShortDramaList(ctx context.Context, param *input.UnlockDramaList) ([]*entity.ShortDramaUnlocks, int, error) {
	shortDramaUnlocks := make([]*entity.ShortDramaUnlocks, 0)
	var count int
	ShortDramaUnlockModel := dao.ShortDramaUnlocks.Ctx(ctx)
	if param.UserId != 0 {
		ShortDramaUnlockModel = ShortDramaUnlockModel.Where("user_id = ?", param.UserId)
	}
	var err error
	if param.Page != 0 && param.PageSize != 0 {
		err = ShortDramaUnlockModel.Page(param.Page, param.PageSize).ScanAndCount(&shortDramaUnlocks, &count, true)
	} else {
		err = ShortDramaUnlockModel.Scan(&shortDramaUnlocks)
	}
	if err != nil {
		g.Log().Error(ctx, "GetUnlockShortDramaList GetList err: ", err)
		return nil, 0, err
	}
	return shortDramaUnlocks, count, nil
}

func (s *orderService) OrderCreate(ctx context.Context, in *input.OrderCreate) (orderInfo *out.OrderEntity, err error) {
	userInfo := middleware.GetUserInfo(ctx)
	if userInfo == nil || userInfo.UserId == 0 {
		return nil, gerror.New("user not exist")
	}
	metrics.HttpOrderCounts.WithLabelValues(strconv.FormatInt(userInfo.UserId, 10), strconv.FormatInt(in.GoodsId, 10))
	if in.GoodsId == 0 {
		return nil, gerror.New("order create err:goods id is 0")
	}
	gModel := dao.Goods.Ctx(ctx)
	//count, err := gModel.Where("id = ?", in.GoodsId).Count()
	//if count <= 0 {
	//	return nil, gerror.New("goods err:goods info not found.")
	//}
	goodsInfo := new(out.Goods)
	err = gModel.Where("id = ?", in.GoodsId).Scan(&goodsInfo)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, gerror.New("商品不存在")
		}
		return nil, gerror.New("goods info err.")
	}
	goodsSku := new(entity.GoodsSku)
	err = dao.GoodsSku.Ctx(ctx).Where("id = ?", goodsInfo.SkuId).Scan(&goodsSku)
	if err != nil {
		return nil, gerror.New("goodsSku err:goodsSku info not found.")
	}
	oModel := dao.Orders.Ctx(ctx)
	r := g.RequestFromCtx(ctx)
	orderInfo = new(out.OrderEntity)
	orderInfo.Id = utility.GetSnowflakeId()
	orderInfo.UserId = userInfo.UserId
	orderInfo.GoodsId = in.GoodsId
	orderInfo.Status = consts.PAY_PENDING
	orderInfo.Amount = goodsSku.Price
	orderInfo.Currency = consts.CurrencyMap[strings.ToUpper(goodsSku.Country)]
	orderInfo.IpAddress = utility.GetClientIp(r)
	orderInfo.UserAgent = utility.GetUserAgent(ctx)
	orderInfo.UserRegisterTime = userInfo.UserRegisterTime
	orderInfo.UserLoginType = userInfo.UserLoginType
	orderInfo.UserSource = userInfo.UserSource
	orderInfo.UserCode = userInfo.UserCode
	orderInfo.App = in.App
	orderInfo.Country = userInfo.Country

	orderRes, err := service.PaymentPayService().CreateOrder(ctx, orderInfo)
	if err != nil {
		return nil, err
	}
	orderInfo.PlatformOrderId = orderRes.ID
	orderInfo.Platform = consts.PAYPALPAYMENT
	// todo 测试paypal获取支付的url
	for _, link := range orderRes.Links {
		if link.Rel == "approve" {
			orderInfo.PayUrl = link.Href
			break
		}
	}

	result, err := oModel.Data(orderInfo).Insert()
	if err != nil {
		g.Log().Error(ctx, "order create err:", err)
		return nil, err
	}
	rowsAffected, err := result.RowsAffected()
	if err != nil {
		return nil, err
	}
	if rowsAffected != 0 {
		return orderInfo, nil
	}

	return nil, gerror.New("order create err.")
}

func (s *orderService) OrderPay(ctx context.Context, in *input.OrderPay) (orderInfo *out.OrderEntity, err error) {
	if in.OrderId == 0 {
		return nil, gerror.New("order pay err:order id is null")
	}
	switch in.Platform {
	case consts.OCEANPAYMENT:
		orderInfo, err = service.OceanPayService().OrderPay(ctx, in)
		if err != nil {
			g.Log().Error(ctx, "pay order err:", err)
			return nil, err
		}
		break
	case consts.PAYPALPAYMENT:
		orderInfo, err = service.PaymentPayService().OrderPay(ctx, in)
		if err != nil {
			g.Log().Error(ctx, "payPal order err:", err)
			return nil, err
		}
		break
	default:
		// TODO 其他支付
		//service.OtherPayService().OrderPay(ctx, in)
		break
	}
	return orderInfo, nil
}
